/**
 * @author haina.z@163.com
 * @brief crc32, 先生成表，再用查表法
 * @version V1.0
 */

/** Includes -----------------------------------------------------------------*/
#include "crc32.h"

/** Macros and constants -----------------------------------------------------*/

/** Type definitions ---------------------------------------------------------*/

/** Private variable definitions (static) ------------------------------------*/
static uint32_t u32CurPoly = 0;
static uint32_t table[256];

/** Static function declarations (prototypes) --------------------------------*/

/** Public variable definitions ----------------------------------------------*/

/** Macros (#define) ---------------------------------------------------------*/

/** Pre-compile check --------------------------------------------------------*/

/** Code ---------------------------------------------------------------------*/

// 位翻转
static uint32_t bitrev(uint32_t input, uint32_t bw)
{
    uint32_t i;
    uint32_t var;
    var = 0;
    for (i = 0; i < bw; i++)
    {
        if (input & 0x01)
        {
            var |= 1 << (bw - 1 - i);
        }
        input >>= 1;
    }
    return var;
}

/**
 * @brief 初始化 生成码表
 * 如:X32+X26+...X1+1,poly=(1<<26)|...|(1<<1)|(1<<0)
 * 
 * @param u32Poly 多项式
 */
void CRC32_Init(uint32_t u32Poly)
{
    uint32_t i;
    uint32_t j;
    uint32_t c;

    if (u32CurPoly == u32Poly)
    {
        return;
    }
    u32CurPoly = u32Poly;

    u32Poly = bitrev(u32Poly, 32);
    for (i = 0; i < 256; i++)
    {
        c = i;
        for (j = 0; j < 8; j++)
        {
            if (c & 1)
            {
                c = u32Poly ^ (c >> 1);
            }
            else
            {
                c = c >> 1;
            }
        }
        table[i] = c;
    }
}

/**
 * @brief 计算 CRC32
 * 
 * @param u32Crc 当前CRC值
 * @param pInput 数据指针
 * @param u32Len 数据长度
 * @return uint32_t 计算之后的CRC32值
 */
uint32_t CRC32_Calculate(uint32_t u32Crc, const void *pInput, uint32_t u32Len)
{
    uint32_t i;
    const uint8_t *pCh;
    uint8_t index;

    pCh = (const uint8_t *)pInput;
    for (i = 0; i < u32Len; i++)
    {
        index = (uint8_t)(u32Crc ^ *pCh);
        u32Crc = (u32Crc >> 8) ^ table[index];
        pCh++;
    }
    return u32Crc;
}

/******************************** End of file *********************************/
